package com.zhb.cloud.encrypt.advice;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;

import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

import com.zhb.cloud.anno.Decrypt;
import com.zhb.cloud.exception.ServiceException;
import com.zhb.cloud.utils.AESEncryptUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * @ClassName: DecryptRequestBodyAdvice
 * @Description:请求数据接收处理类 对加了@Decrypt的方法的数据进行解密操作只对@RequestBody参数有效
 * @author: zhb1316783262@163.com
 * @date: 2019年3月6日下午2:51:55
 */
@RestControllerAdvice
@Slf4j
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {

	@Value("${encrypt.key}")
	private String key;

	@Override
	public boolean supports(MethodParameter methodParameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) {
		return true;
	}

	@Override
	public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
			Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
		return body;
	}

	@Override
	public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) throws IOException {
		if (parameter.getMethod().isAnnotationPresent(Decrypt.class)) {
			try {
				return new DecryptHttpInputMessage(inputMessage, key);
			} catch (Exception e) {
				log.error("解密异常", e);
				throw new ServiceException("数据参数解析错误");
			}
		}
		return inputMessage;
	}

	@Override
	public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,
			Class<? extends HttpMessageConverter<?>> converterType) {
		return body;
	}
}

@Slf4j
class DecryptHttpInputMessage implements HttpInputMessage {
	private HttpHeaders headers;
	private InputStream body;
	public static final String CHARSET = "UTF-8";

	public DecryptHttpInputMessage(HttpInputMessage inputMessage, String key) throws Exception {
		this.headers = inputMessage.getHeaders();
		String content = IOUtils.toString(inputMessage.getBody(), CHARSET);
		log.info("解密签报文:[{}]", content);
		String decryptContent = new String(AESEncryptUtil.decrypt(content, key), "UTF-8");
		log.info("解密后报文:[{}]", decryptContent);
		this.body = IOUtils.toInputStream(decryptContent, CHARSET);
	}

	@Override
	public InputStream getBody() throws IOException {
		return body;
	}

	@Override
	public HttpHeaders getHeaders() {
		return headers;
	}
}
